<html lang="zh-CN">
<head>
  <meta charset="utf-8">
  <title>文档</title>
  
  <link href="../css/semantic/semantic.min.css" rel="stylesheet">
  <link href="../css/markdown.css" rel="stylesheet">
  <link href="../css/wtxynavigation.css" rel="stylesheet">
  <script src="../js/jquery.min.js"></script>
  <script type="text/javascript" src="../js/include.js"></script>

  <style>
    body{padding-top:0;background:#f7f7f7}
    body>.ui.container{width:100%;padding:0}
    #project-title{background:#6e6e6e;width:100%;line-height:3.572rem;color:#fff;font-size:1.2rem}
    #project-title .title-wrap{font-weight:700;padding:0 12px;width:100%;max-width:1366px!important;min-width:900px;margin:0 auto}
    #project-title .left,#project-title right{display:inline-block}
    #project-title .right{float:right}
    #project-title .right .wiki-actions .menu{left:auto;right:0;margin-top:.4em!important}
    #wiki-preview-container{width:100%;max-width:1366px!important;min-width:900px;padding:0;border:1px solid #e3e9ed;border-top:0}
    #wiki-preview>.ui.segment{margin-top:0;padding:1rem;padding-left:0;border:0}
    .hover-places{display:inline-block}
    #page-detail{width:60%;margin:0 auto}
    #page-detail .title{font-weight:700;font-size:24px;padding:12px 0;border-bottom:1px solid #ccc}
    #page-detail .content{margin-top:15px}
    .content p{word-wrap:break-word}
    #wiki-parent,#wiki-title,#wikis{display:none}
    .ui.grid{padding:0!important}
    #ex-all{cursor:pointer;color:#537c8d}
  </style>
</head>
<body>
  <div class="ui container">
    <div id="project-title">
      <div class="title-wrap">
        <div class="left">
          <i class="icon eye"></i>
          文档预览:
          mianmSDK
        </div>
        <div class="right">
          Export by Gitee
        </div>
      </div>
    </div>

    <div class="ui container" id="wiki-preview-container">
      <div id="wiki-preview">
        <div class="ui segment">
          <div id="page-detail" class="markdown-body">
            <div class='title'>35.Runloop常驻线程</div><div class='content'><h1>
<a id="线程和runloop" class="anchor" href="#%E7%BA%BF%E7%A8%8B%E5%92%8Crunloop"></a>线程和Runloop</h1>
<p><strong>关键词</strong>: <code>runloop</code>,<code>常驻线程</code></p>
<ol>
<li>线程和<strong>Runloop</strong>是一一对应的</li>
<li>自己创建的线程默认是没有<strong>Runloop</strong>的, 需要自己手动创建</li>
</ol>
<h1>
<a id="runloop常驻线程" class="anchor" href="#runloop%E5%B8%B8%E9%A9%BB%E7%BA%BF%E7%A8%8B"></a>Runloop常驻线程</h1>
<p>做法如下:</p>
<ol>
<li>为当前线程开启一个<strong>Runloop</strong>
</li>
<li>向改<strong>Runloop</strong>中添加一个 <strong>Port/Source</strong>, 或者添加一个<strong>Timer</strong>来维持<strong>Runloop</strong>的事件循环</li>
<li>启动<strong>Runloop</strong>
</li>
</ol>
<h1>
<a id="1-方法一-添加timer" class="anchor" href="#1-%E6%96%B9%E6%B3%95%E4%B8%80-%E6%B7%BB%E5%8A%A0timer"></a>1. 方法一 添加timer</h1>
<pre><code>
#import "ViewController.h"

#import "XYThread.h"

/**
 ====================================================================================
 
                                使用Timer方式做常驻线程
 
 ====================================================================================
 */

@interface ViewController ()

@property (nonatomic, strong) XYThread * thread;
@property (nonatomic, assign) NSInteger count;
@property (nonatomic, strong) NSTimer *timer;


@property (nonatomic, strong) XYThread * thread2;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    
    self.thread = [[XYThread alloc] initWithTarget:self selector:@selector(execute) object:nil];
    [self.thread start];
    
    // 测试其他线程会不会死!!!!!!!!!
    [self test2];
}

- (void)execute
{
    NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(getNetworkStatus) userInfo:nil repeats:YES];
    
    _timer = timer;
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
    [[NSRunLoop currentRunLoop] run];
    
    NSLog(@"runloop 挂了......打印了没?");
}




- (void)getNetworkStatus
{
    NSLog(@"获取网络状态, 没网了的话提醒一下~, 再看看当前线程: %@", [NSThread currentThread]);
}



- (void)otherMethod
{
    self.count++;
    NSLog(@"%s, , 再看看当前线程: %@", __func__, [NSThread currentThread]);
    
    if (self.count == 5) {
        
        
        // 移除timer可以停掉runloop
        CFRunLoopRef runLoopRef = CFRunLoopGetCurrent();
        CFRunLoopRemoveTimer(runLoopRef, (CFRunLoopTimerRef)self.timer, kCFRunLoopDefaultMode);
        
        // 干掉线程也能 停掉runloop
        NSLog(@"count: %zd  杀死thread, 停止runloop", self.count);
//        [self.thread cancel];
//        [NSThread exit];
//        self.thread = nil;
        
    }
}


- (void)touchesBegan:(NSSet&lt;UITouch *&gt; *)touches withEvent:(UIEvent *)event
{
    [self performSelector:@selector(otherMethod) onThread:self.thread withObject:nil waitUntilDone:NO];
}











/**
 ====================================================================================
 
                                测试这个线程会不会死!!!!!!!!!
 
 ====================================================================================
 */

- (void)test2
{
    self.thread2 = [[XYThread alloc] initWithTarget:self selector:@selector(execute2) object:nil];
    [self.thread2 start];
}

- (void)execute2
{
    NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(getNetworkStatus2) userInfo:nil repeats:YES];
    
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
    [[NSRunLoop currentRunLoop] run];
    
    
}

- (void)getNetworkStatus2
{
    NSLog(@"22222********获取网络状态, 没网了的话提醒一下~, 再看看当前线程: %@", [NSThread currentThread]);
}
@end



</code></pre>
<h1>
<a id="2-方法二-添加nsport" class="anchor" href="#2-%E6%96%B9%E6%B3%95%E4%BA%8C-%E6%B7%BB%E5%8A%A0nsport"></a>2. 方法二 添加NSPort</h1>
<pre><code>
//
//  ViewController.m
//  study
//
//  Created by codew on 5/31/21.
//

#import "ViewController.h"

#import "XYThread.h"

/**
 ====================================================================================
 
                                使用NSPort方式做常驻线程
 
 ====================================================================================
 */

@interface ViewController ()

@property (nonatomic, strong) XYThread * thread;
@property (nonatomic, assign) NSInteger count;

@property (nonatomic, strong) NSPort * port;


@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    
    self.thread = [[XYThread alloc] initWithTarget:self selector:@selector(execute) object:nil];
    [self.thread start];
    
    
}

- (void)execute
{
    self.port = [NSPort port];
    [[NSRunLoop currentRunLoop] addPort:self.port forMode:NSDefaultRunLoopMode];
    [[NSRunLoop currentRunLoop] run];
//
    
    
    NSLog(@"runloop 挂了......打印了没?");
}




- (void)methodRun
{
    
    
    self.count++;
    NSLog(@"%s, , 再看看当前线程: %@", __func__, [NSThread currentThread]);
    
    if (self.count == 5) {
        
        
        // 移除 NSPort 并不会停止runloop
//        CFRunLoopRef runLoopRef = CFRunLoopGetCurrent();
//        [[NSRunLoop currentRunLoop] removePort:self.port forMode:NSDefaultRunLoopMode];
        
        
        
        // 干掉线程也能 停掉runloop
        NSLog(@"count: %zd  杀死thread, 停止runloop", self.count);
        [self.thread cancel];
        [NSThread exit];
        self.thread = nil;
        
    }
}





- (void)touchesBegan:(NSSet&lt;UITouch *&gt; *)touches withEvent:(UIEvent *)event
{
    [self performSelector:@selector(methodRun) onThread:self.thread withObject:nil waitUntilDone:YES];
}


@end


</code></pre>
<h1>
<a id="3-方法三-使用cf接口" class="anchor" href="#3-%E6%96%B9%E6%B3%95%E4%B8%89-%E4%BD%BF%E7%94%A8cf%E6%8E%A5%E5%8F%A3"></a>3. 方法三 使用CF接口</h1>
<pre><code>
//
//  WTObject.m
//  study
//
//  Created by codew on 5/31/21.
//

#import "WTObject.h"

@interface WTObject ()
{
    CFRunLoopSourceRef source;
}

@end

@implementation WTObject

static NSThread *thread = nil;
static BOOL runAlways = YES;

+ (NSThread *)threadForDispatch
{
    if (thread == nil) {
        
        @synchronized (self) {
            
            if (thread == nil) {
                
                thread = [[NSThread alloc] initWithTarget:self selector:@selector(execute) object:nil];
                [thread setName:@"com.itopengl.thread"];
                [thread start];
            }
        }
    }
    
    return thread;
}


+ (void)execute
{
    // 创建一个 Source
    
    CFRunLoopSourceContext context = {0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,NULL};
    CFRunLoopSourceRef source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &amp;context);
    CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
    
    while (runAlways) {
        
        @autoreleasepool {
            
            CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0e10, true);
            
        }
    }
    
    
    CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
    CFRelease(source);
    
}
@end


</code></pre>
<h3>
<a id="1" class="anchor" href="#1"></a>1.</h3>
<h1>
<a id="答" class="anchor" href="#%E7%AD%94"></a>答:</h1></div>
          </div>
        </div>
      </div>
      </div>
  </div>
</body>
</html>